package com.copro.chemdb.stat.rule;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.ihelpuoo.db.sql.SQLSegment;
import org.ihelpuoo.util.Properties;

import com.copro.chemdb.ques.QuesUtils;
import com.copro.chemdb.ques.Questionnaire;
import com.copro.chemdb.result.Result;
import com.copro.chemdb.result.ResultUtils;
import com.copro.chemdb.stat.AbstractStatRule;
import com.copro.chemdb.stat.StatResult;
import com.copro.chemdb.subject.Subject;
import com.copro.chemdb.subject.SubjectUtils;
import com.copro.simple.Application;
import com.copro.simple.SimpleException;
import com.copro.simple.db.QueryCallback;

public class Rule3C2 extends AbstractStatRule {

	class StatCounter implements QueryCallback {

		private List<List<Object>> rows;
		private Map<Integer, Result> reSet;
		private List<Subject> subjects;
		private Application app;

		public StatCounter(Application app, List<Subject> children) {
			this.app = app;
			this.rows = new ArrayList<List<Object>>();
			this.reSet = new HashMap<Integer, Result>();
			subjects = children;
		}

		public List<List<Object>> get() {
			return this.rows;
		}

		@Override
		public void exec(ResultSet rs) throws SQLException {
			Object[] row = null;
			while (rs.next()) {
				/* get result */
				int reId = rs.getInt("resultId");
				Result re = retriveResult(reId);
				Result pre = retriveResult(re.getParentId());
				/* get parent result */
				row = new Object[subjects.size() + 2];
				row[0] = pre.getBrief();
				row[1] = re.getBrief();
				do {
					if (rs.getInt("resultId") != re.getId()) {
						addOneRow(row);
						row = null;
						rs.previous();
						break;
					} else {
						int suId = rs.getInt("subjectId");
						int index = 0;
						for (index = 0; index < subjects.size(); index++) {
							if (subjects.get(index).getId() == suId)
								break;
						}
						row[index + 2] = rs.getString("value");
					}
				} while (rs.next());
				if (null != row)
					addOneRow(row);
			}
			// sort it
			Collections.sort(rows, new Comparator<List<Object>>() {
				public int compare(List<Object> l1, List<Object> l2) {
					return ((String) l1.get(0)).compareTo((String) l2.get(0));
				};
			});
		}

		private void addOneRow(Object[] row) {
			ArrayList<Object> arr = new ArrayList<Object>(row.length);
			for (int j = 0; j < row.length; j++)
				arr.add(null == row[j] ? "&nbsp;" : row[j]);
			rows.add(arr);
		}

		private Result retriveResult(int reId) throws SQLException {
			Result re = reSet.get(reId);
			if (null == re) {
				try {
					re = ResultUtils.getResult(app, reId);
				} catch (SimpleException e) {
					throw new SQLException(e);
				}
				this.reSet.put(reId, re);
			}
			return re;
		}
	}

	@Override
	public StatResult doStat(Application app, Subject subject, int statType)
			throws SimpleException {
		List<Subject> children = SubjectUtils.queryChildrenQuesSubjects(app,
				subject);
		int len = 0;
		StatCounter callback = new StatCounter(app, children);
		String ids = generateIds(children);
		Questionnaire ques = QuesUtils.getById(app, subject.getQuesId());
		SQLSegment sql = app.getSQL("rule3c2.stat");
		sql.set("ids", ids);
		sql.set("quesId", ques.getId());
		sql.set("type", statType);
		app.query(sql.toString(), callback);

		sql = app.getSQL("rule3c2.count");
		sql.set("ids", ids);
		sql.set("type", statType);
		len = app.getCount(sql.toString());

		Hashtable<String, Object> result = new Hashtable<String, Object>();
		result.put("count", len);
		result.put("rows", callback.get());
		result.put("text", subject.getBrief());
		result.put("subjects", callback.subjects);
		return new StatResult("rule3c2", result);
	}

	private String generateIds(List<Subject> children) {
		StringBuffer sb = new StringBuffer();
		Iterator<Subject> it = children.iterator();
		while (it.hasNext()) {
			sb.append(it.next().getId());
			if (it.hasNext())
				sb.append(',');
		}
		String ids = sb.toString();
		return ids;
	}

	@Override
	public void setup(Properties conf) {
	}

}
